const sharp = require('sharp');
const TextToSVG = require('text-to-svg');
const path = require('path');
const { classes } = require('./classes');
var parseString = require('xml2js').parseString;

function getFontImg(_path, text, fontSize, letterSpacing) {
    const svgStr = TextToSVG.loadSync(path.resolve(__dirname, _path)).getSVG(text, {
        fontSize: fontSize,
        anchor: 'left top',
        letterSpacing: letterSpacing ? letterSpacing : 0
    });
    let size = {
        w: 0,
        h: 0
    }
    parseString(svgStr, { attrkey: 'attrs' }, (err, { svg }) => {
        size.w = +svg.attrs.width;
        size.h = +svg.attrs.height;
    });

    return [Buffer.from(
        svgStr
    ), size];
}

function getAddrText(text) {
    let brnum = 0;
    let textArr = [];
    text.split('').forEach(t => {
        brnum += isNaN(parseInt(t)) ? 1 : 0.5;
    });
    let n = Math.ceil(brnum / 11);
    for (let i = 0; i < n; i++) {
        textArr[i] = text.slice(i * 11, 11 * (i + 1));
    }
    let _size = { w: 0, h: 0 }
    return [textArr.map((t, i) => {
        let [input, size] = getFontImg('./fonts/hei.ttf', t, 33);
        _size.w = Math.max(size.w, _size.w);
        _size.h += +size.h;
        return {
            input,
            left: 335,
            top: 535 + 48 * i
        };
    }), _size];
}

function validateConfig(config) {
    return [
        'name',
        'sex',
        'nation',
        'year',
        'mon',
        'day',
        // 'org',
        // 'validTerm',
        'addr',
        'idn',
        'avatar'
    ].find(e => {
        return !config[e];
    })
}

async function getAvatar(img) {
    try {
        const imgBuffer = await sharp(path.resolve(process.cwd(), img))
        .resize({
            width: 270,
            height: 330
        })
        .png()
        .toBuffer();
        return [imgBuffer, { w: 270, h: 330 }];
    } catch(e) {
        console.error(e);
        return [];
    }
}
function genComponents(config, { left, top }) {
    return Promise.all(Object.keys(config).map(async (key) => {
        let item = classes[key];
        let txt = config[key];
        let img, _size;
        switch (key) {
            case 'avatar':
                [img, _size] = await getAvatar(txt);
                break;
            case 'addr':
                [img, _size] = getAddrText(txt);
                img.forEach(imgItem => {
                    imgItem.left -= left;
                    imgItem.top -= top;
                });
                break;
            default:
                [img, _size] = getFontImg(
                    item.font,
                    txt,
                    item.fontSize,
                    item.letterSpacing
                );
        }
        return {
            _key: key,
            input: img,
            _size,
            left: (typeof item.left === 'function' ? item.left(txt) : item.left) - left,
            top: item.top - top
        }
    }))

}

function composite(config) {
    return new Promise(async (resolve, reject) => {
        let test = validateConfig(config);
        if (!config || test !== undefined) {
            reject(new Error(`缺少参数：${test}`));
            return false;
        };
        const { left, top } = config.resizeinfo || { left: 0, top: 0 };
        const components = await genComponents(config, { left, top });
        const positionInfo = components.map((item, index) => {
            return [index,  item.left, item.top, item._size.w, item._size.h];
        });

        const imgComponents = components.map((item) => {
            if (Array.isArray(item.input)) {
                return item.input.map((item) => item)
            }
            return item;
        }).flat();
        const pipPng = sharp(path.resolve(__dirname, './images/empty.png'));
        config.resizeinfo && pipPng.extract(config.resizeinfo || [])
        pipPng.composite(
            imgComponents
        )
            .png()
            .toBuffer()
            .then((e) => {
                resolve([e, positionInfo])
            })
            .catch(reject);
    });
}

module.exports = composite;
